/**
 * @file test_image.cpp
 * @author 心流 (iFlow CLI)
 * @brief 测试OpenCL图像对象创建和管理功能
 * @version 0.1
 * @date 2025-11-27
 *
 * @copyright Copyright (c) 2025
 *
 */
#define BOOST_TEST_MODULE TestImage
#include <CL/cl.h>

#include <boost/format.hpp>
#include <boost/test/included/unit_test.hpp>
#include <boost/timer/timer.hpp>
#include <vector>

#include "wrapper.hpp"
#include "utility.hpp"

// 测试使用clCreateImage创建2D图像
BOOST_AUTO_TEST_CASE(TestCreateImage2D)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    cl_context   context = cl.GetContext();
    cl_device_id device  = cl.GetDeviceID();
    BOOST_CHECK(context != nullptr);
    BOOST_CHECK(device != nullptr);

    // 检查设备是否支持图像
    cl_bool image_support = CL_FALSE;
    cl_int  err           = clGetDeviceInfo(device,
                          CL_DEVICE_IMAGE_SUPPORT,
                          sizeof(image_support),
                          &image_support,
                          nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    if (image_support == CL_FALSE)
    {
        std::cout << "Device does not support images, skipping test" << std::endl;
        cl.DeInit();
        return;
    }

    // 定义图像格式
    cl_image_format format;
    format.image_channel_order     = CL_RGBA;
    format.image_channel_data_type = CL_UNSIGNED_INT8;

    // 定义图像描述符
    cl_image_desc desc;
    desc.image_type       = CL_MEM_OBJECT_IMAGE2D;
    desc.image_width      = 256;
    desc.image_height     = 256;
    desc.image_depth      = 0;
    desc.image_array_size = 0;
    desc.image_row_pitch  = 0;
    desc.image_slice_pitch = 0;
    desc.num_mip_levels   = 0;
    desc.num_samples      = 0;
    desc.mem_object       = nullptr;

    // 创建图像
    cl_mem image = clCreateImage(
        context, CL_MEM_READ_WRITE, &format, &desc, nullptr, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(image != nullptr);

    // 验证图像对象
    cl_mem_object_type obj_type;
    err = clGetMemObjectInfo(
        image, CL_MEM_TYPE, sizeof(obj_type), &obj_type, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(obj_type == CL_MEM_OBJECT_IMAGE2D);

    size_t width = 0;
    err          = clGetImageInfo(
        image, CL_IMAGE_WIDTH, sizeof(width), &width, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(width == 256);

    size_t height = 0;
    err           = clGetImageInfo(
        image, CL_IMAGE_HEIGHT, sizeof(height), &height, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(height == 256);

    // 清理
    err = clReleaseMemObject(image);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl.DeInit();
}

// 测试使用clCreateImage创建3D图像
BOOST_AUTO_TEST_CASE(TestCreateImage3D)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    cl_context   context = cl.GetContext();
    cl_device_id device  = cl.GetDeviceID();
    BOOST_CHECK(context != nullptr);
    BOOST_CHECK(device != nullptr);

    // 检查设备是否支持图像
    cl_bool image_support = CL_FALSE;
    cl_int  err           = clGetDeviceInfo(device,
                          CL_DEVICE_IMAGE_SUPPORT,
                          sizeof(image_support),
                          &image_support,
                          nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    if (image_support == CL_FALSE)
    {
        std::cout << "Device does not support images, skipping test" << std::endl;
        cl.DeInit();
        return;
    }

    // 检查设备是否支持3D图像
    size_t max_3d_width = 0;
    // CL_DEVICE_MAX_3D_IMAGE_SIZE 在OpenCL 1.0中未定义，使用更通用的检查方式
    // 简单地尝试创建3D图像，不预先检查设备能力

    // 定义图像格式
    cl_image_format format;
    format.image_channel_order     = CL_RGBA;
    format.image_channel_data_type = CL_UNSIGNED_INT8;

    // 定义图像描述符
    cl_image_desc desc;
    desc.image_type       = CL_MEM_OBJECT_IMAGE3D;
    desc.image_width      = 64;
    desc.image_height     = 64;
    desc.image_depth      = 64;
    desc.image_array_size = 0;
    desc.image_row_pitch  = 0;
    desc.image_slice_pitch = 0;
    desc.num_mip_levels   = 0;
    desc.num_samples      = 0;
    desc.mem_object       = nullptr;

    // 创建3D图像
    cl_mem image = clCreateImage(
        context, CL_MEM_READ_WRITE, &format, &desc, nullptr, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(image != nullptr);

    // 验证3D图像对象
    cl_mem_object_type obj_type;
    err = clGetMemObjectInfo(
        image, CL_MEM_TYPE, sizeof(obj_type), &obj_type, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(obj_type == CL_MEM_OBJECT_IMAGE3D);

    size_t width = 0;
    err          = clGetImageInfo(
        image, CL_IMAGE_WIDTH, sizeof(width), &width, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(width == 64);

    size_t height = 0;
    err           = clGetImageInfo(
        image, CL_IMAGE_HEIGHT, sizeof(height), &height, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(height == 64);

    size_t depth = 0;
    err          = clGetImageInfo(
        image, CL_IMAGE_DEPTH, sizeof(depth), &depth, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(depth == 64);

    // 清理
    err = clReleaseMemObject(image);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl.DeInit();
}

// 测试使用clCreateImage创建1D图像
BOOST_AUTO_TEST_CASE(TestCreateImage1D)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    cl_context   context = cl.GetContext();
    cl_device_id device  = cl.GetDeviceID();
    BOOST_CHECK(context != nullptr);
    BOOST_CHECK(device != nullptr);

    // 检查设备是否支持图像
    cl_bool image_support = CL_FALSE;
    cl_int  err           = clGetDeviceInfo(device,
                          CL_DEVICE_IMAGE_SUPPORT,
                          sizeof(image_support),
                          &image_support,
                          nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    if (image_support == CL_FALSE)
    {
        std::cout << "Device does not support images, skipping test" << std::endl;
        cl.DeInit();
        return;
    }

    // 定义图像格式
    cl_image_format format;
    format.image_channel_order     = CL_RGBA;
    format.image_channel_data_type = CL_UNSIGNED_INT8;

    // 定义图像描述符
    cl_image_desc desc;
    desc.image_type       = CL_MEM_OBJECT_IMAGE1D;
    desc.image_width      = 512;
    desc.image_height     = 0;
    desc.image_depth      = 0;
    desc.image_array_size = 0;
    desc.image_row_pitch  = 0;
    desc.image_slice_pitch = 0;
    desc.num_mip_levels   = 0;
    desc.num_samples      = 0;
    desc.mem_object       = nullptr;

    // 创建1D图像
    cl_mem image = clCreateImage(
        context, CL_MEM_READ_WRITE, &format, &desc, nullptr, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(image != nullptr);

    // 验证1D图像对象
    cl_mem_object_type obj_type;
    err = clGetMemObjectInfo(
        image, CL_MEM_TYPE, sizeof(obj_type), &obj_type, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(obj_type == CL_MEM_OBJECT_IMAGE1D);

    size_t width = 0;
    err          = clGetImageInfo(
        image, CL_IMAGE_WIDTH, sizeof(width), &width, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(width == 512);

    // 清理
    err = clReleaseMemObject(image);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl.DeInit();
}

// 测试图像对象信息查询
BOOST_AUTO_TEST_CASE(TestImageInfo)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    cl_context   context = cl.GetContext();
    cl_device_id device  = cl.GetDeviceID();
    BOOST_CHECK(context != nullptr);
    BOOST_CHECK(device != nullptr);

    // 检查设备是否支持图像
    cl_bool image_support = CL_FALSE;
    cl_int  err           = clGetDeviceInfo(device,
                          CL_DEVICE_IMAGE_SUPPORT,
                          sizeof(image_support),
                          &image_support,
                          nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    if (image_support == CL_FALSE)
    {
        std::cout << "Device does not support images, skipping test" << std::endl;
        cl.DeInit();
        return;
    }

    // 定义图像格式
    cl_image_format format;
    format.image_channel_order     = CL_RGBA;
    format.image_channel_data_type = CL_UNSIGNED_INT8;

    // 定义图像描述符
    cl_image_desc desc;
    desc.image_type       = CL_MEM_OBJECT_IMAGE2D;
    desc.image_width      = 128;
    desc.image_height     = 128;
    desc.image_depth      = 0;
    desc.image_array_size = 0;
    desc.image_row_pitch  = 0;
    desc.image_slice_pitch = 0;
    desc.num_mip_levels   = 0;
    desc.num_samples      = 0;
    desc.mem_object       = nullptr;

    // 创建图像
    cl_mem image = clCreateImage(
        context, CL_MEM_READ_WRITE, &format, &desc, nullptr, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(image != nullptr);

    // 测试查询各种图像信息
    cl_image_format queried_format;
    err = clGetImageInfo(
        image, CL_IMAGE_FORMAT, sizeof(queried_format), &queried_format, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(queried_format.image_channel_order == CL_RGBA);
    BOOST_CHECK(queried_format.image_channel_data_type == CL_UNSIGNED_INT8);

    size_t element_size = 0;
    err                 = clGetImageInfo(
        image, CL_IMAGE_ELEMENT_SIZE, sizeof(element_size), &element_size, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(element_size, 0);

    size_t row_pitch = 0;
    err              = clGetImageInfo(
        image, CL_IMAGE_ROW_PITCH, sizeof(row_pitch), &row_pitch, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    // 对于2D图像，row_pitch可能为0（表示没有填充）或非0（表示实际行字节数）

    size_t slice_pitch = 0;
    err                = clGetImageInfo(image,
                          CL_IMAGE_SLICE_PITCH,
                          sizeof(slice_pitch),
                          &slice_pitch,
                          nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    // 对于2D图像，slice_pitch应为0

    cl_uint num_mip_levels = 0;
    err = clGetImageInfo(image,
                         CL_IMAGE_NUM_MIP_LEVELS,
                         sizeof(num_mip_levels),
                         &num_mip_levels,
                         nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(num_mip_levels == 0);  // 我们创建时设置为0

    cl_uint num_samples = 0;
    err                 = clGetImageInfo(
        image, CL_IMAGE_NUM_SAMPLES, sizeof(num_samples), &num_samples, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(num_samples == 0);  // 我们创建时设置为0

    // 清理
    err = clReleaseMemObject(image);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl.DeInit();
}

// 测试图像对象错误处理
BOOST_AUTO_TEST_CASE(TestImageErrorHandling)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    cl_context   context = cl.GetContext();
    cl_device_id device  = cl.GetDeviceID();
    BOOST_CHECK(context != nullptr);
    BOOST_CHECK(device != nullptr);

    // 检查设备是否支持图像
    cl_bool image_support = CL_FALSE;
    cl_int  err           = clGetDeviceInfo(device,
                          CL_DEVICE_IMAGE_SUPPORT,
                          sizeof(image_support),
                          &image_support,
                          nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    if (image_support == CL_FALSE)
    {
        std::cout << "Device does not support images, skipping test" << std::endl;
        cl.DeInit();
        return;
    }

    // 定义图像格式
    cl_image_format format;
    format.image_channel_order     = CL_RGBA;
    format.image_channel_data_type = CL_UNSIGNED_INT8;

    // 定义图像描述符
    cl_image_desc desc;
    desc.image_type       = CL_MEM_OBJECT_IMAGE2D;
    desc.image_width      = 128;
    desc.image_height     = 128;
    desc.image_depth      = 0;
    desc.image_array_size = 0;
    desc.image_row_pitch  = 0;
    desc.image_slice_pitch = 0;
    desc.num_mip_levels   = 0;
    desc.num_samples      = 0;
    desc.mem_object       = nullptr;

    // 测试使用无效上下文创建图像（应该失败）
    cl_mem image = clCreateImage(
        nullptr, CL_MEM_READ_WRITE, &format, &desc, nullptr, &err);
    BOOST_CHECK_NE(err, CL_SUCCESS);  // 应该失败
    BOOST_CHECK(image == nullptr);

    // 使用有效上下文正常创建图像
    image = clCreateImage(
        context, CL_MEM_READ_WRITE, &format, &desc, nullptr, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(image != nullptr);

    // 测试查询无效图像的信息（应该失败）
    cl_mem_object_type obj_type;
    err = clGetMemObjectInfo(
        nullptr, CL_MEM_TYPE, sizeof(obj_type), &obj_type, nullptr);
    BOOST_CHECK_NE(err, CL_SUCCESS);  // 应该失败

    // 正常查询有效图像信息
    err = clGetMemObjectInfo(
        image, CL_MEM_TYPE, sizeof(obj_type), &obj_type, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 正常清理图像
    err = clReleaseMemObject(image);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl.DeInit();
}

// 测试图像对象的引用计数
BOOST_AUTO_TEST_CASE(TestImageReferenceCounting)
{
    CLWrapper cl;
    bool      init_result = cl.Init();
    BOOST_CHECK(init_result == true);

    cl_context   context = cl.GetContext();
    cl_device_id device  = cl.GetDeviceID();
    BOOST_CHECK(context != nullptr);
    BOOST_CHECK(device != nullptr);

    // 检查设备是否支持图像
    cl_bool image_support = CL_FALSE;
    cl_int  err           = clGetDeviceInfo(device,
                          CL_DEVICE_IMAGE_SUPPORT,
                          sizeof(image_support),
                          &image_support,
                          nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    if (image_support == CL_FALSE)
    {
        std::cout << "Device does not support images, skipping test" << std::endl;
        cl.DeInit();
        return;
    }

    // 定义图像格式
    cl_image_format format;
    format.image_channel_order     = CL_RGBA;
    format.image_channel_data_type = CL_UNSIGNED_INT8;

    // 定义图像描述符
    cl_image_desc desc;
    desc.image_type       = CL_MEM_OBJECT_IMAGE2D;
    desc.image_width      = 64;
    desc.image_height     = 64;
    desc.image_depth      = 0;
    desc.image_array_size = 0;
    desc.image_row_pitch  = 0;
    desc.image_slice_pitch = 0;
    desc.num_mip_levels   = 0;
    desc.num_samples      = 0;
    desc.mem_object       = nullptr;

    // 创建图像
    cl_mem image = clCreateImage(
        context, CL_MEM_READ_WRITE, &format, &desc, nullptr, &err);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK(image != nullptr);

    // 测试获取内存对象信息（包括引用计数）
    cl_uint ref_count = 0;
    err               = clGetMemObjectInfo(
        image, CL_MEM_REFERENCE_COUNT, sizeof(ref_count), &ref_count, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(ref_count, 0);

    // 增加引用计数
    err = clRetainMemObject(image);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    // 检查引用计数是否增加
    cl_uint new_ref_count = 0;
    err = clGetMemObjectInfo(image,
                             CL_MEM_REFERENCE_COUNT,
                             sizeof(new_ref_count),
                             &new_ref_count,
                             nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(new_ref_count, ref_count);

    // 释放两次以完全清理（一次对应retain，一次对应create）
    err = clReleaseMemObject(image);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    err = clReleaseMemObject(image);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl.DeInit();
}